'''
Created on 29.01.2012

@author: myaut
'''

import salsa

from xml.etree.ElementTree import parse as xml_parse
from xml.etree.ElementTree import dump as xml_dump

class ConfigException(salsa.SALSAException):
    def __init__(self, message, element=None):
        salsa.SALSAException.__init__(self, message)
        
        if element is not None:
            self.xml_text = xml_dump(element)

class Config:
    def __init__(self, config_path):
        self.config_path = config_path
        
        try:
            self.config_file = open(config_path, 'r')
        except IOError:
            raise ConfigException('Config file %s couldn\'t be opened' % config_path)
        
        self.config_xml = xml_parse(self.config_file)
        self.process_config()
        
        self.read_config = True
    
    def get_global_var(self, key):
        return self.globals[key]
    
    def get_globals(self):
        return self.globals
    
    def try_find(self, element, match):
        el = element.find(match)
        
        if el is None:
            raise ConfigException('Incorrect configuration file %s: missing section %s' % 
                                    (self.config_path, match), element)
            
        return el  
    
    def get_section(self, name):
        return self.try_find(self.root, name)
    
    def process_config(self):
        self.root = self.config_xml.getroot()
        
        if self.root.tag != 'configuration':
            raise ConfigException('Incorrect configuration file %s: wrong root' % (self.config_path), self.root)
        
        self.globals = self.process_parameters(self.get_section('globalSettings'), 
                                                required=['core_port', 'data_dir', 'bin_dir'], 
                                                default={'core_host': 'localhost'})
    
    def process_list(self, element, tag, req_attrs=[], default={}, need_el_ref=False):
        ellist = element.findall(tag)
        cfglist = []
        
        req_attr_set = set(req_attrs)
        
        for el in ellist: 
            attr = default.copy()
            attr.update(el.attrib)
            
            if need_el_ref:
                attr['_el'] = el
            
            el_attr_set = set(attr.keys())
            
            if not el_attr_set >= req_attr_set:
                raise ConfigException('Incorrect configuration file %s: missing required attributes [%s]' % 
                                    (self.config_path), ','.join(list(req_attr_set - el_attr_set)), el)
            
            cfglist.append(attr)
        
        return cfglist
    
    def process_parameters(self, element, required=[], default={}):
        param_list = self.process_list(element, 'parameter', ['name', 'value'])
        param_dict = default.copy()
        
        for param in param_list:
            param_dict[param['name']] = param['value']
        
        missing_params = list(set(required) - set(param_dict.keys()))
        
        if len(missing_params) > 0:
            raise ConfigException('Incorrect configuration file %s: missing required parameters [%s]' % 
                                    (self.config_path, ','.join(missing_params)), element)
        
        return param_dict    